package com.mercury.base.result;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.util.StdConverter;
import com.mercury.base.exception.MercuryException;
import com.mercury.base.result.code.BaseCode;
import com.mercury.base.result.code.IRespCode;
import com.mercury.base.util.StringUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nullable;
import java.beans.Transient;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

import static java.util.stream.Stream.of;

/**
 * @author mercury
 * @date 2020/10/11 2:33 下午
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonPropertyOrder({"code", "message", "data"})
public abstract class BaseResultCoreResult<E> implements ResultBasics {

    @ApiModelProperty(value = "业务码", dataType = "java.lang.Integer", required = true, position = 1)
    @JsonSerialize(converter = StringToIntegerConverter.class)
    protected String code;

    @ApiModelProperty(value = "业务码说明", required = true, example = "SUCCESS", position = 2)
    protected String message;

    @ApiModelProperty(value = "业务数据", position = 100)
    protected E data;

    @Transient
    @JSONField(serialize = false)
    protected IRespCode[] getOkCodes() {
        return new IRespCode[]{BaseCode.SUCCESS};
    }

    @Transient
    @JSONField(serialize = false)
    public boolean isSuccess() {
        // 兼容
        return "00000000".equals(code) || of(getOkCodes()).anyMatch(respOkCode -> Objects.equals(this.code, respOkCode.getRespCode()));
    }

    @Transient
    @JSONField(serialize = false)
    public boolean isError() {
        return !isSuccess();
    }

    @Transient
    @JSONField(serialize = false)
    public IRespCode getRespCode() {
        return new IRespCode() {
            @Override
            public String getCode() {
                return code;
            }

            @Override
            public String getMessage() {
                return message;
            }
        };
    }

    public RuntimeException decomposeException() {
        return new MercuryException(getRespCode());
    }

    @Override
    public Map<String, Object> toMap() {
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("code", StringToIntegerConverter.INSTANCE.convert(code));
        map.put("message", message);
        map.put("data", data);
        return map;
    }

    private static final String GLOBAL_SUCCESS_CODE = System.getProperty("api.result.success_code");

    public String getCode() {
        if (StringUtils.isNotBlank(GLOBAL_SUCCESS_CODE) && isSuccess()) {
            return GLOBAL_SUCCESS_CODE;
        }
        return this.code;
    }

    static class StringToIntegerConverter extends StdConverter<String, Object> {

        static final StringToIntegerConverter INSTANCE = new StringToIntegerConverter();

        @Override
        public Object convert(String value) {
            if (StringUtils.isNotBlank(GLOBAL_SUCCESS_CODE)) {
                return value;
            }
            return StringUtil.parseInt(value);
        }
    }


    @Nullable
    public static String trim(String s) {
        return s == null ? null : s.trim();
    }

}
